package br.com.felix.fwt.ui;

import java.awt.event.ActionEvent;
import java.io.PrintWriter;

import br.com.felix.fwt.security.exception.UnauthorizedAccessException;
import br.com.felix.fwt.ui.exception.ComponentRenderException;
import br.com.felix.fwt.ui.exception.UserInterfaceInitializationException;
import br.com.felix.fwt.util.IdGenerator;


/**
 * <p>
 * This class provides the interface used
 * to add behavior to the framework's components.
 * </p>
 * <p>
 * The actionName must be unique within a form. 
 * It's the actionName that will be used to determine which
 * of the form's ActionListener is to be called.
 * </p>
 * <p>
 * The changesInterfacesComponents value is very important. This is because the
 * framework (the FelixWebToolkitServlet) maintains a Hash with the components to improve performance (so the framework has no need to navigate the component 
 * tree to update component values). This Hash is the same across multiple user requests.
 * So, if you add new components with new Action Listener, you MUST notify the framework. Otherwise
 * the new components won't have the desired behavior.
 * And you do this by setting the changesInterfacesComponents to TRUE.
 * </p> 
 * 
 * <p>
 * You may notice that the BaseComponent has a actionListener. But, currently, only the Button component
 * actually implements the actionListener.
 * This is because the ActionListener is meant to cause a form submit (as this is the listener to Java methods),
 * and most of the time we will make form submits only with button clicks.
 * </p>
 * 
 * @see ActionEvent
 */
public abstract class ActionListener implements Renderable {

	/** The action name. Must be unique within a Form. */
	public String actionName; 
	
	/** Number used to generate random names. */
	private static int id = 0;
	
	/** The changes interfaces components property signals the framework that new components
	 * are added when the actionPerformed is run, and that the framework must re-register the components that have ActionListeners. */
	public boolean changesInterfacesComponents;
	
	/**
     * Instantiates a new action listener.
     * The actionName is generated "randomly".
     * {@link #changesInterfacesComponents} is set to TRUE.
     * 
     */
    public ActionListener(){
        this.changesInterfacesComponents = true;
    }
	
	
	/**
	 * Instantiates a new action listener.
	 * The actionName is generated "randomly".
	 * 
	 * @param changesInterfaceComponents signals that when the actionPerformed method is run, new components with ActionListeners are added to the component tree.
	 */
	public ActionListener(boolean changesInterfaceComponents){
		this.changesInterfacesComponents = changesInterfaceComponents;
	}
	
	

	/**
	 * Generates a "random" name for the action listener.
	 * */
	public void generateName(IdGenerator idGen){
		if (this.actionName == null) {
			int id = idGen.getNextId();
			this.actionName = "userAction" + (id);
		}
	}


	/**
	 * Instantiates a new action listener.
	 * The changesInterfacesComponents property is set to FALSE.
	 * 
	 * @param name the name of this action. Must be unique within a form. No checking is made.
	 */
	public ActionListener(String name){
		this.actionName = name;
		this.changesInterfacesComponents = false;
	}
	
	
	/**
	 * Instantiates a new action listener.
	 * 
	 * @param name the name of the action.
	 * @param changesInterfaceComponents signals that when the actionPerformed method is run, new components with ActionListeners are added to the component tree.
	 */
	public ActionListener(String name, boolean changesInterfaceComponents){
		this.actionName = name;
		this.changesInterfacesComponents = changesInterfaceComponents;
	}
	
	/**
	 * This method has the code to be executed when the "action is performed".
	 * Usually a button click submitting the form.
	 * 
	 * After the code is run, we can tell the framework which form it will now present
	 * to the user return the appropriate form object.
	 * 
	 * @return the form is the form that will be presented to the user, after the method is executed.
	 * @throws UserInterfaceInitializationException when an exception prevents a user interface component to initialize properly.
	 * 
	 */
	public abstract Form actionPerformed() throws UserInterfaceInitializationException, UnauthorizedAccessException;


	@Override
	public void write(PrintWriter out) throws ComponentRenderException {
		out.write(" onclick=\"javascript:document.forms[0].actionName.value='"+actionName+"';document.forms[0].submit();\" ");
	}
	
}
